/*******************************************************************************
 * Copyright (c) 2002 Boris Pruessmann and others. All rights reserved. This
 * program and the accompanying materials are made available under the terms of
 * the Common Public License v0.5 which accompanies this distribution, and is
 * available at http://www.eclipse.org/legal/cpl-v05.html
 * 
 * Contributors: Boris Pruessmann - Initial implementation.
 ******************************************************************************/
package net.sourceforge.perforce.ui.internal.dnd;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;

import net.sourceforge.perforce.core.PerforceCorePlugin;
import net.sourceforge.perforce.core.api.IFileType;
import net.sourceforge.perforce.core.api.IPerforceServer;
import net.sourceforge.perforce.core.api.IPerforceServerManager;
import net.sourceforge.perforce.core.resources.IP4File;

import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.swt.dnd.ByteArrayTransfer;
import org.eclipse.swt.dnd.TransferData;

/**
 * @version $Revision: 488 $
 * @author <a href="mailto:bpruessmann@users.sourceforge.net">Boris
 *         Pruessmann</a>
 */
public class LocalFileTransfer extends ByteArrayTransfer {
  // ---------------------------------------------------------------------------
  // Private Constants

  /** Stores the singleton instance. */
  private static final LocalFileTransfer INSTANCE = new LocalFileTransfer();

  /**
   * Create a unique ID to make sure that different Eclipse applications use
   * different "types" of <code>ResourceTransfer</code>
   */
  private static final String TYPE_NAME = "resource-transfer-format:" + System.currentTimeMillis() + //$NON-NLS-1$
      ":" + INSTANCE.hashCode(); //$NON-NLS-1$

  /** Stores the type id of the unique TYPE_NAME */
  private static final int TYPE_ID = registerType(TYPE_NAME);

  // -----------------------------------------------------------------------
  // Public Static Methods

  /**
   * Call this method to retrieve the LocalFileTransfer singleton.
   * 
   * @return the singleton instance
   */
  public static final LocalFileTransfer getInstance() {
    return INSTANCE;
  }

  // ------------------------------------------------------------------------
  // Private Constructors

  /** Constructor for LocalFileTransfer. */
  private LocalFileTransfer() {
  }

  // ---------------------------------------------------------------------------
  // Protected Methods

  @Override
  protected int[] getTypeIds() {
    return new int[] {TYPE_ID};
  }

  @Override
  protected String[] getTypeNames() {
    return new String[] {TYPE_NAME};
  }

  @Override
  protected void javaToNative(Object data, TransferData transferData) {
    if (!(data instanceof IP4File[])) {
      return;
    }

    IP4File[] localFiles = (IP4File[]) data;

    ByteArrayOutputStream os = null;
    DataOutputStream dos = null;
    try {
      os = new ByteArrayOutputStream();
      dos = new DataOutputStream(os);

      dos.writeInt(localFiles.length);
      for (int i = 0; i < localFiles.length; i++) {
        writeLocalFile(dos, localFiles[i]);
      }

      super.javaToNative(os.toByteArray(), transferData);
    } catch (IOException e) {
      // it's best to send nothing if there were problems
    } finally {
      try {
        if (dos != null) {
          dos.close();
        }

        if (os != null) {
          os.close();
        }
      } catch (IOException e) {
        // Ignored!
      }
    }
  }

  @Override
  protected Object nativeToJava(TransferData transferData) {
    byte[] bytes = (byte[]) super.nativeToJava(transferData);
    if (bytes == null) {
      return new IP4File[0];
    }

    ByteArrayInputStream is = null;
    DataInputStream dis = null;
    try {
      is = new ByteArrayInputStream(bytes);
      dis = new DataInputStream(is);

      int count = dis.readInt();
      IP4File[] result = new IP4File[count];

      for (int i = 0; i < count; i++) {
        result[i] = readLocalFile(dis);
      }

      return result;
    } catch (IOException e) {
      // it's best to send nothing if there were problems
      return new IP4File[0];
    } finally {
      try {
        if (dis != null) {
          dis.close();
        }

        if (is != null) {
          is.close();
        }
      } catch (IOException e) {
        // Ignored!
      }
    }

  }

  //----------------------------------------------------------------------------
  // - Private Methods

  /**
   * Called to write the given LoaclFile to the specified DataOutputStream.
   * 
   * @param dos the DataOutputStream
   * @param localFile the LocalFile instance.
   * 
   * @throws IOException in case of an I/O error.
   */
  private void writeLocalFile(DataOutputStream dos, IP4File localFile) throws IOException {
    dos.writeUTF(localFile.getServer().getUniqueName());
    dos.writeUTF(localFile.getLocation().toOSString());
  }

  /**
   * Called to read LocalFile instances from the given DataInputStream.
   * 
   * @param dis the DataInputStream.
   * @return the LocalFile instance that was read.
   * @throws IOException in case of an I/O error
   */
  private IP4File readLocalFile(DataInputStream dis) throws IOException {
    String uniqueName = dis.readUTF();
    IPerforceServerManager manager = PerforceCorePlugin.getServerManager();
    final IPerforceServer server = manager.getPerforceServer(uniqueName);

    String absolutePath = dis.readUTF();
    final IPath location = new Path(absolutePath);

    return new IP4File() {
      public Integer getChangelistId() {
        return null;
      }

      public boolean isResolved() {
        return false;
      }

      public boolean needsResolve() {
        return false;
      }

      public boolean hasOurLock() {
        return false;
      }

      public String getName() {
        return null;
      }

      public String getDepotFilename() {
        return null;
      }

      public IPath getLocation() {
        return location;
      }

      public Integer getRevision() {
        return null;
      }

      public String getAction() {
        return null;
      }

      public String getClientName() {
        return null;
      }

      public IFileType getFileType() {
        return null;
      }

      public IPerforceServer getServer() {
        return server;
      }
    };
  }
}
